package com.zhongan.gateway.filter;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.zhongan.gateway.bean.Developer;
import com.zhongan.gateway.common.constant.GwDeveloperApiConstant;
import com.zhongan.gateway.common.enums.GatewayErrorCodeEnum;
import com.zhongan.gateway.common.enums.ResponseCodeEnum;
import com.zhongan.gateway.common.exception.GatewayException;
import com.zhongan.gateway.dto.RequestBase;
import com.zhongan.gateway.dto.ResponseBase;
import com.zhongan.gateway.service.DeveloperService;
import com.zhongan.gateway.service.SecurityService;

/**
 * api调用次数记录
 */
@Component
public class RoutResponseZuulFilter extends ZuulFilter {

    private Logger           logger = LoggerFactory.getLogger(RoutResponseZuulFilter.class);

    @Resource
    private DeveloperService developerService;

    @Resource
    private SecurityService  securityService;

    @Override
    public String filterType() {
        return "post";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        HttpServletRequest request = RequestContext.getCurrentContext().getRequest();

        String uri = request.getRequestURI();
        if (uri != null && uri.startsWith(GwDeveloperApiConstant.COMMON_GROOVY_URL)) {
            return false;
        }

        return null == request.getAttribute("gatewayException");
    }

    @Override
    public Object run() {
        String res = "";
        logger.info("调用api结束,开始封装返回值...");
        HttpServletRequest request = RequestContext.getCurrentContext().getRequest();

        try {
            //读取返回值
            res = getResStr();
            logger.info("response={}", res);
        } catch (Exception e) {
            GatewayException ge = new GatewayException(GatewayErrorCodeEnum.UN_KNOWN.getCode(),
                    GatewayErrorCodeEnum.UN_KNOWN.getMsg());
            request.setAttribute("gatewayException", ge);
            logger.error("解析返回值失败, " + e.getMessage(), e);

        }
        if (StringUtils.isEmpty(res)) {
            throw new RuntimeException("调用api返回值为空 ");
        }
        //组装返回值
        ResponseBase responseBase = getResponseBase(res);

        RequestBase re = (RequestBase) request.getAttribute("requestBase");
        Developer dev = developerService.selectDeveloperByAppKey(re.getAppKey());
        //对返回值加密签名
        encryptSignRes(responseBase, dev, request);
        request.setAttribute("responseClear", res);
        request.setAttribute("responseBase", responseBase);
        setResStatus(request);
        logger.info("封装返回值完成...");
        return null;

    }

    private void setResStatus(HttpServletRequest request) {
        Integer code = (Integer) request.getAttribute("res_status");
        if (null == code) {
            request.setAttribute("res_status", 200);
        }
    }

    private ResponseBase getResponseBase(String res) {
        Long time = System.currentTimeMillis();
        ResponseBase responseBase = new ResponseBase();
        responseBase.setCode(ResponseCodeEnum.SUCCESS.getCode());
        responseBase.setBizContent(res);
        responseBase.setTimestamp(time.toString());
        return responseBase;
    }

    public String getResStr() throws Exception {
        String res = (String) RequestContext.getCurrentContext().get("res");
        if (StringUtils.isEmpty(res)) {
            InputStream is = RequestContext.getCurrentContext().getResponseDataStream();

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int i = -1;
            while (is != null && (i = is.read()) != -1) {
                baos.write(i);
            }
            res = baos.toString();
        }

        return res;
    }

    private void encryptSignRes(ResponseBase responseBase, Developer dev, HttpServletRequest request) {

        try {
            securityService.encryptAndSign(responseBase, dev.getPublicKey(), dev.getEncryptType());

        } catch (GatewayException e) {
            request.setAttribute("gatewayException", e);
            throw new RuntimeException("加密返回值失败 ");
        }

    }

}
